home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 26 / Cream of the Crop 26.iso / os2 / timidsrc.zip / ncurs_c.c < prev    next >
C/C++ Source or Header  |  1996-05-21  |  12KB  |  541 lines

  1. /* 
  2.  
  3.     TiMidity -- Experimental MIDI to WAVE converter
  4.     Copyright (C) 1995 Tuukka Toivonen <toivonen@clinet.fi>
  5.  
  6.     This program is free software; you can redistribute it and/or modify
  7.     it under the terms of the GNU General Public License as published by
  8.     the Free Software Foundation; either version 2 of the License, or
  9.     (at your option) any later version.
  10.  
  11.     This program is distributed in the hope that it will be useful,
  12.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.     GNU General Public License for more details.
  15.  
  16.     You should have received a copy of the GNU General Public License
  17.     along with this program; if not, write to the Free Software
  18.     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  19.  
  20.     ncurs_c.c
  21.    
  22.     */
  23.  
  24. #include <stdio.h>
  25. #include <stdlib.h>
  26. #include <unistd.h>
  27. #include <stdarg.h>
  28.  
  29. #include <ncurses.h>
  30.  
  31. #include "config.h"
  32. #include "common.h"
  33. #include "instrum.h"
  34. #include "playmidi.h"
  35. #include "output.h"
  36. #include "controls.h"
  37.  
  38. static void ctl_refresh(void);
  39. static void ctl_help_mode(void);
  40. static void ctl_total_time(int tt);
  41. static void ctl_master_volume(int mv);
  42. static void ctl_file_name(char *name);
  43. static void ctl_current_time(int ct);
  44. static void ctl_note(int v);
  45. static void ctl_program(int ch, int val);
  46. static void ctl_volume(int channel, int val);
  47. static void ctl_expression(int channel, int val);
  48. static void ctl_panning(int channel, int val);
  49. static void ctl_sustain(int channel, int val);
  50. static void ctl_pitch_bend(int channel, int val);
  51. static void ctl_reset(void);
  52. static int ctl_open(int using_stdin, int using_stdout);
  53. static void ctl_close(void);
  54. static int ctl_read(int32 *valp);
  55. static int cmsg(int type, int verbosity_level, char *fmt, ...);
  56.  
  57. /**********************************************/
  58. /* export the interface functions */
  59.  
  60. #define ctl ncurses_control_mode
  61.  
  62. ControlMode ctl= 
  63. {
  64.   "ncurses interface", 'n',
  65.   1,0,0,
  66.   ctl_open,dumb_pass_playing_list, ctl_close, ctl_read, cmsg,
  67.   ctl_refresh, ctl_reset, ctl_file_name, ctl_total_time, ctl_current_time, 
  68.   ctl_note, 
  69.   ctl_master_volume, ctl_program, ctl_volume, 
  70.   ctl_expression, ctl_panning, ctl_sustain, ctl_pitch_bend
  71. };
  72.  
  73.  
  74. /***********************************************************************/
  75. /* foreground/background checks disabled since switching to curses */
  76. /* static int in_foreground=1; */
  77. static int ctl_helpmode=0;
  78.  
  79. static WINDOW *dftwin=0, *msgwin=0;
  80.  
  81. static void _ctl_refresh(void)
  82. {
  83.   wmove(dftwin, 0,0);
  84.   wrefresh(dftwin);
  85. }
  86.  
  87. static void ctl_refresh(void)
  88. {
  89.   if (ctl.trace_playing)
  90.     _ctl_refresh();
  91. }
  92.  
  93. static void ctl_help_mode(void)
  94. {
  95.   static WINDOW *helpwin;
  96.   if (ctl_helpmode)
  97.     {
  98.       ctl_helpmode=0;
  99.       delwin(helpwin);
  100.       touchwin(dftwin);
  101.       _ctl_refresh();
  102.     }
  103.   else
  104.     {
  105.       ctl_helpmode=1;
  106.       /* And here I thought the point of curses was that you could put
  107.      stuff on windows without having to worry about whether this
  108.      one is overlapping that or the other way round... */
  109.       helpwin=newwin(2,COLS,0,0);
  110.       wattron(helpwin, A_REVERSE);
  111.       werase(helpwin); 
  112.       waddstr(helpwin, 
  113.           "V/Up=Louder    b/Left=Skip back      "
  114.           "n/Next=Next file      r/Home=Restart file");
  115.       wmove(helpwin, 1,0);
  116.       waddstr(helpwin, 
  117.           "v/Down=Softer  f/Right=Skip forward  "
  118.           "p/Prev=Previous file  q/End=Quit program");
  119.       wrefresh(helpwin);
  120.     }
  121. }
  122.  
  123. static void ctl_total_time(int tt)
  124. {
  125.   int mins, secs=tt/play_mode->rate;
  126.   mins=secs/60;
  127.   secs-=mins*60;
  128.  
  129.   wmove(dftwin, 4,6+6+3);
  130.   wattron(dftwin, A_BOLD);
  131.   wprintw(dftwin, "%3d:%02d", mins, secs);
  132.   wattroff(dftwin, A_BOLD);
  133.   _ctl_refresh();
  134. }
  135.  
  136. static void ctl_master_volume(int mv)
  137. {
  138.   wmove(dftwin, 4,COLS-5);
  139.   wattron(dftwin, A_BOLD);
  140.   wprintw(dftwin, "%03d %%", mv);
  141.   wattroff(dftwin, A_BOLD);
  142.   _ctl_refresh();
  143. }
  144.  
  145. static void ctl_file_name(char *name)
  146. {
  147.   wmove(dftwin, 3,6);
  148.   wclrtoeol(dftwin );
  149.   wattron(dftwin, A_BOLD);
  150.   waddstr(dftwin, name);
  151.   wattroff(dftwin, A_BOLD);
  152.   _ctl_refresh();
  153. }
  154.  
  155. static void ctl_current_time(int ct)
  156. {
  157.   int i,v;
  158.   int mins, secs=ct/play_mode->rate;
  159.   if (!ctl.trace_playing) 
  160.     return;
  161.  
  162.   mins=secs/60;
  163.   secs-=mins*60;
  164.   wmove(dftwin, 4,6);
  165.   wattron(dftwin, A_BOLD);
  166.   wprintw(dftwin, "%3d:%02d", mins, secs);
  167.   v=0;
  168.   i=voices;
  169.   while (i--)
  170.     if (voice[i].status!=VOICE_FREE) v++;
  171.   wmove(dftwin, 4,48);
  172.   wprintw(dftwin, "%2d", v);
  173.   wattroff(dftwin, A_BOLD);
  174.   _ctl_refresh();
  175. }
  176.  
  177. static void ctl_note(int v)
  178. {
  179.   int xl;
  180.   if (!ctl.trace_playing) 
  181.     return;
  182.   xl=voice[v].note%(COLS-24);
  183.   wmove(dftwin, 8+voice[v].channel,xl+3);
  184.   switch(voice[v].status)
  185.     {
  186.     case VOICE_DIE:
  187.       waddch(dftwin, ',');
  188.       break;
  189.     case VOICE_FREE: 
  190.       waddch(dftwin, '.');
  191.       break;
  192.     case VOICE_ON:
  193.       wattron(dftwin, A_BOLD);
  194.       waddch(dftwin, '0'+(10*voice[v].velocity)/128); 
  195.       wattroff(dftwin, A_BOLD);
  196.       break;
  197.     case VOICE_OFF:
  198.     case VOICE_SUSTAINED:
  199.       waddch(dftwin, '0'+(10*voice[v].velocity)/128);
  200.       break;
  201.     }
  202. }
  203.  
  204. static void ctl_program(int ch, int val)
  205. {
  206.   if (!ctl.trace_playing) 
  207.     return;
  208.   wmove(dftwin, 8+ch, COLS-20);
  209.   if (ISDRUMCHANNEL(ch))
  210.     {
  211.       wattron(dftwin, A_BOLD);
  212.       wprintw(dftwin, "%03d", val);
  213.       wattroff(dftwin, A_BOLD);
  214.     }
  215.   else
  216.     wprintw(dftwin, "%03d", val);
  217. }
  218.  
  219. static void ctl_volume(int channel, int val)
  220. {
  221.   if (!ctl.trace_playing) 
  222.     return;
  223.   wmove(dftwin, 8+channel, COLS-16);
  224.   wprintw(dftwin, "%3d", (val*100)/127);
  225. }
  226.  
  227. static void ctl_expression(int channel, int val)
  228. {
  229.   if (!ctl.trace_playing) 
  230.     return;
  231.   wmove(dftwin, 8+channel, COLS-12);
  232.   wprintw(dftwin, "%3d", (val*100)/127);
  233. }
  234.  
  235. static void ctl_panning(int channel, int val)
  236. {
  237.   if (!ctl.trace_playing) 
  238.     return;
  239.   wmove(dftwin, 8+channel, COLS-8);
  240.   if (val==NO_PANNING)
  241.     waddstr(dftwin, "   ");
  242.   else if (val<5)
  243.     waddstr(dftwin, " L ");
  244.   else if (val>123)
  245.     waddstr(dftwin, " R ");
  246.   else if (val>60 && val<68)
  247.     waddstr(dftwin, " C ");
  248.   else
  249.     {
  250.       /* wprintw(dftwin, "%+02d", (100*(val-64))/64); */
  251.       val = (100*(val-64))/64; /* piss on curses */
  252.       if (val<0)
  253.     {
  254.       waddch(dftwin, '-');
  255.       val=-val;
  256.     }
  257.       else waddch(dftwin, '+');
  258.       wprintw(dftwin, "%02d", val);
  259.     }
  260. }
  261.  
  262. static void ctl_sustain(int channel, int val)
  263. {
  264.   if (!ctl.trace_playing) 
  265.     return;
  266.   wmove(dftwin, 8+channel, COLS-4);
  267.   if (val) waddch(dftwin, 'S');
  268.   else waddch(dftwin, ' ');
  269. }
  270.  
  271. static void ctl_pitch_bend(int channel, int val)
  272. {
  273.   if (!ctl.trace_playing) 
  274.     return;
  275.   wmove(dftwin, 8+channel, COLS-2);
  276.   if (val>0x2000) waddch(dftwin, '+');
  277.   else if (val<0x2000) waddch(dftwin, '-');
  278.   else waddch(dftwin, ' ');
  279. }
  280.  
  281. static void ctl_reset(void)
  282. {
  283.   int i,j;
  284.   if (!ctl.trace_playing) 
  285.     return;
  286.   for (i=0; i<16; i++)
  287.     {
  288.       wmove(dftwin, 8+i, 3);
  289.       for (j=0; j<COLS-24; j++)
  290.     waddch(dftwin, '.');
  291.       ctl_program(i, channel[i].program);
  292.       ctl_volume(i, channel[i].volume);
  293.       ctl_expression(i, channel[i].expression);
  294.       ctl_panning(i, channel[i].panning);
  295.       ctl_sustain(i, channel[i].sustain);
  296.       ctl_pitch_bend(i, channel[i].pitchbend);
  297.     }
  298.   _ctl_refresh();
  299. }
  300.  
  301. /***********************************************************************/
  302.  
  303. /* #define CURSED_REDIR_HACK */
  304.  
  305. #ifdef CURSED_REDIR_HACK
  306. static SCREEN *oldscr;
  307. #endif
  308.  
  309. static int ctl_open(int using_stdin, int using_stdout)
  310. {
  311.   int i;
  312. #ifdef CURSED_REDIR_HACK
  313.   FILE *infp=stdin, *outfp=stdout;
  314.   SCREEN *dftscr;
  315.  
  316.   /* This doesn't work right */
  317.   if (using_stdin && using_stdout)
  318.     {
  319.       infp=outfp=stderr;
  320.       fflush(stderr);
  321.       setvbuf(stderr, 0, _IOFBF, BUFSIZ);
  322.     }
  323.   else if (using_stdout)
  324.     {
  325.       outfp=stderr;
  326.       fflush(stderr);
  327.       setvbuf(stderr, 0, _IOFBF, BUFSIZ);
  328.     }
  329.   else if (using_stdin)
  330.     {
  331.       infp=stdout;
  332.       fflush(stdout);
  333.       setvbuf(stdout, 0, _IOFBF, BUFSIZ);
  334.     }
  335.  
  336.   dftscr=newterm(0, outfp, infp);
  337.   if (!dftscr)
  338.     return -1;
  339.   oldscr=set_term(dftscr);
  340.   /* dftwin=stdscr; */
  341. #else
  342.   initscr();
  343. #endif
  344.  
  345.   cbreak();
  346.   noecho();
  347.   nonl();
  348.   nodelay(stdscr, 1);
  349.   scrollok(stdscr, 0);
  350.   idlok(stdscr, 1);
  351.   keypad(stdscr, TRUE);
  352.   ctl.opened=1;
  353.  
  354.   if (ctl.trace_playing)
  355.     dftwin=stdscr;
  356.   else
  357.     dftwin=newwin(6,COLS,0,0);
  358.  
  359.   werase(dftwin);
  360.   wmove(dftwin, 0,0);
  361.   waddstr(dftwin, "TiMidity v" TIMID_VERSION);
  362.   wmove(dftwin, 0,COLS-52);
  363.   waddstr(dftwin, "(C) 1995 Tuukka Toivonen <toivonen@clinet.fi>");
  364.   wmove(dftwin, 1,0);
  365.   waddstr(dftwin, "Press 'h' for help with keys, or 'q' to quit.");
  366.   wmove(dftwin, 3,0);
  367.   waddstr(dftwin, "File:");
  368.   wmove(dftwin, 4,0);
  369.   if (ctl.trace_playing)
  370.     {
  371.       waddstr(dftwin, "Time:");
  372.       wmove(dftwin, 4,6+6+1);
  373.       waddch(dftwin, '/');
  374.       wmove(dftwin, 4,40);
  375.       wprintw(dftwin, "Voices:    / %d", voices);
  376.     }
  377.   else
  378.     {
  379.       waddstr(dftwin, "Playing time:");
  380.     }
  381.   wmove(dftwin, 4,COLS-20);
  382.   waddstr(dftwin, "Master volume:");
  383.   wmove(dftwin, 5,0);
  384.   for (i=0; i<COLS; i++)
  385.     waddch(dftwin, '_');
  386.   if (ctl.trace_playing)
  387.     {
  388.       wmove(dftwin, 6,0);
  389.       waddstr(dftwin, "Ch");
  390.       wmove(dftwin, 6,COLS-20);
  391.       waddstr(dftwin, "Prg Vol Exp Pan S B");
  392.       wmove(dftwin, 7,0);
  393.       for (i=0; i<COLS; i++)
  394.     waddch(dftwin, '-');
  395.       for (i=0; i<16; i++)
  396.     {
  397.       wmove(dftwin, 8+i, 0);
  398.       wprintw(dftwin, "%02d", i+1);
  399.     }
  400.     }
  401.   else
  402.     {
  403.       msgwin=newwin(LINES-6,COLS,6,0);
  404.       werase(msgwin);
  405.       scrollok(msgwin, 1);
  406.       wrefresh(msgwin);
  407.     }
  408.   _ctl_refresh();
  409.   
  410.   return 0;
  411. }
  412.  
  413. static void ctl_close(void)
  414. {
  415.   if (ctl.opened)
  416.     {
  417.       endwin();
  418.       ctl.opened=0;
  419.     }
  420. }
  421.  
  422. static int ctl_read(int32 *valp)
  423. {
  424.   int c;
  425.   while ((c=getch())!=ERR)
  426.     {
  427.       switch(c)
  428.     {
  429.     case 'h':
  430.     case '?':
  431.     case KEY_F(1):
  432.       ctl_help_mode();
  433.       return RC_NONE;
  434.       
  435.     case 'V':
  436.     case KEY_UP:
  437.       *valp=10;
  438.       return RC_CHANGE_VOLUME;
  439.     case 'v':
  440.     case KEY_DOWN:
  441.       *valp=-10;
  442.       return RC_CHANGE_VOLUME;
  443.     case 'q':
  444.     case KEY_END:
  445.       return RC_QUIT;
  446.     case 'n':
  447.     case KEY_NPAGE:
  448.       return RC_NEXT;
  449.     case 'p':
  450.     case KEY_PPAGE:
  451.       return RC_REALLY_PREVIOUS;
  452.     case 'r':
  453.     case KEY_HOME:
  454.       return RC_RESTART;
  455.  
  456.     case 'f':
  457.     case KEY_RIGHT:
  458.       *valp=play_mode->rate;
  459.       return RC_FORWARD;
  460.     case 'b':
  461.     case KEY_LEFT:
  462.       *valp=play_mode->rate;
  463.       return RC_BACK;
  464.       /* case ' ':
  465.          return RC_TOGGLE_PAUSE; */
  466.     }
  467.     }
  468.   return RC_NONE;
  469. }
  470.  
  471. static int cmsg(int type, int verbosity_level, char *fmt, ...)
  472. {
  473.   va_list ap;
  474.   if ((type==CMSG_TEXT || type==CMSG_INFO || type==CMSG_WARNING) &&
  475.       ctl.verbosity<verbosity_level)
  476.     return 0;
  477.   va_start(ap, fmt);
  478.   if (!ctl.opened)
  479.     {
  480.       vfprintf(stderr, fmt, ap);
  481.       fprintf(stderr, "\n");
  482.     }
  483.   else if (ctl.trace_playing)
  484.     {
  485.       switch(type)
  486.     {
  487.       /* Pretty pointless to only have one line for messages, but... */
  488.     case CMSG_WARNING:
  489.     case CMSG_ERROR:
  490.     case CMSG_FATAL:
  491.       wmove(dftwin, 2,0);
  492.       wclrtoeol(dftwin);
  493.       wattron(dftwin, A_REVERSE);
  494.       vwprintw(dftwin, fmt, ap);
  495.       wattroff(dftwin, A_REVERSE);
  496.       _ctl_refresh();
  497.       if (type==CMSG_WARNING)
  498.         sleep(1); /* Don't you just _HATE_ it when programs do this... */
  499.       else
  500.         sleep(2);
  501.       wmove(dftwin, 2,0);
  502.       wclrtoeol(dftwin);
  503.       _ctl_refresh();
  504.       break;
  505.     }
  506.     }
  507.   else
  508.     {
  509.       switch(type)
  510.     {
  511.     default:
  512.       vwprintw(msgwin, fmt, ap);
  513.       wprintw(msgwin, "\n");
  514.       wrefresh(msgwin);
  515.       break;
  516.  
  517.     case CMSG_WARNING:
  518.       wattron(msgwin, A_BOLD);
  519.       vwprintw(msgwin, fmt, ap);
  520.       wprintw(msgwin, "\n");
  521.       wattroff(msgwin, A_BOLD);
  522.       wrefresh(msgwin);
  523.       break;
  524.       
  525.     case CMSG_ERROR:
  526.     case CMSG_FATAL:
  527.       wattron(msgwin, A_REVERSE);
  528.       vwprintw(msgwin, fmt, ap);
  529.       wprintw(msgwin, "\n");
  530.       wattroff(msgwin, A_REVERSE);
  531.       wrefresh(msgwin);
  532.       if (type==CMSG_FATAL)
  533.         sleep(2);
  534.       break;
  535.     }
  536.     }
  537.  
  538.   va_end(ap);
  539.   return 0;
  540. }
  541.